docs(pm): os-verify-lock's ordering header states headship's one measured exception — a resuming slot (#15581) - #15760
Conversation
…ured exception The ordering block justified head-only `flock` with "headship is stable — tickets sort by arrival and the ones ahead of you can only disappear" (47c1021, #9921). True when written, and overtaken six days later by the slot mechanism (c312a56, #12335): a parked slot keeps its ORIGINAL arrival stamp and re-enters the live queue at that stamp on resume, so a ticket ahead of you can now APPEAR. Nothing sent that change back to re-read the sentence. Both measured halves are now written down (#15581): the exception, and the bound on it — a resuming slot cannot displace an incumbent head already blocked inside `flock`, because that caller left the queue loop and never re-reads its position, so the slip is exactly one position and is spent only against callers that are merely polling. The one-position slip is recorded as ACCEPTED with its price attached (one holder's hold: p50 95s, p90 418s, max 643s on the ledger as read for #14944) rather than quietly corrected, and the known unfixed boundary is stated: re-checking headship per 30s slice does not close the window, and `flock -n` plus polling is a contract change to the ordering layer and the maintainer's, not a fix on sight. Four self-test cases pin both halves, using the battery's existing multi-party harness on its PRIVATE lock (OS_VERIFY_LOCK_FILE, from which the queue, ledger and boots paths derive) — the shared /tmp lock is not touched. No behaviour change: the diff is the header block plus self-test cases. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…rify-lock-headship-invariant
|
ACCEPT — PR #15760 (head The ordering block now states both measured halves exactly as ruled (a resuming slot re-enters at its original stamp so a ticket ahead can APPEAR — Measured by this seat: branch script placed at Dev-filed #15763 ( Flip + arm when both required jobs report success on Generated by Claude Code |
|
Flipped ready + auto-merge enabled (06:55Z, Generated by Claude Code |
Fixes #15581
Prose correction of the ordering block in
scripts/pm/os-verify-lock.sh, plus four self-test cases that pin it. No behaviour change — nothing in the acquisition path, the queue, the slot mechanism orflockis touched.Before / after
The bullet justifying head-only
flockended, at:68on main:That sentence was true when written (
47c1021b4, #9921, 2026-08-19) and was overtaken six days later by the slot mechanism (c312a562e, #12335, 2026-08-25), which had no reason to come back and re-read it. It now states both measured halves:flock: once a caller leaves the queue loop at position 1 it never re-reads its position, so the ordering layer has nothing left to ask it to yield with. The resumed place is delivered against callers that are merely polling, and against nobody else. The slip is exactly one position.The header also now records, per triage's condition, that the one-position slip is accepted rather than unnoticed, with its price attached — one holder's hold, p50 95s / p90 418s / max 643s on the ledger as read for #14944, flagged as a reading of that ledger at that time and not a constant this script measures — and the known, unfixed boundary: re-checking headship after each failed
flockslice does not close the window (SLICE_Sis 30s, so a slot resuming inside the last slice before a release still loses), and tightening further means abandoning blockingflockforflock -nplus polling, which is a contract change to the ordering layer and the maintainer's, not a fix on sight.Self-test: harness already existed, so the case was added
The
--self-testbattery already drives real multi-party scenarios (one holder plus staggered children, a SIGKILLed slot owner, a three-waiter FIFO case) against a private lock. So the card's three-party case was added rather than declined.Isolation, quoted from the code rather than asserted. The suite exports its own lock file and every other path derives from it:
and in the script proper the derivations are
LOCK_FILEfromOS_VERIFY_LOCK_FILE(:329),QUEUE_DIR/HOLDER_FILEfromLOCK_FILE(:338,:339),LEDGER_FILE(:344),BOOTS_FILE(:1069). The shared/tmp/os-heavy-verify.lock, its ledger and its boots file are never named by any test, and--statusread the shared lock asstate: lock is free,queue: emptyboth before and after this work.Four cases, at
da4bb1651:Scenario, exactly the card's: one holder; a polite caller that obeys a 2s budget, times out and parks; newcomer A (only live ticket, so it takes the head and blocks in
flock); newcomer B (position 2, polling); the returner resuming the parked place with a stamp older than either newcomer. Acquisition orderA R B, and the live queue read while A is insideflockhas the returner's ticket sorting first.Why the third case is not flaky. It rests on the incumbent winning the wake race between two blocked
flockwaiters. Measured before pinning it: 14/14 reproductions ofARBin an isolated harness (6 idle, 8 with the box loaded to a 1-minute load average of 11.7), and 15/15 first-blocker-won at the raw primitive on this kernel.Verification
Exit codes captured before any pipe; verdict lines quoted as the gate printed them.
os-verify-lock.sh --self-test(before)EXIT=0—✓ os-verify-lock self-test: all cases pass.· 225 casesos-verify-lock.sh --self-test(after, atda4bb1651)EXIT=0— same verdict line · 229 cases, 0 failures (+4 named above) · 1m43sos-verify-lock.sh --statusbefore / after0/0, identical shape — only the ledger record count advanced (457 → 459, other seats' runs)bash -n scripts/pm/os-verify-lock.shEXIT=0shellcheckPATHand not innode_modules/.binorigin/mainmode_self_test— zero non-comment change anywhere in the acquisition pathdispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstackEXIT=0, derived from the tree atda4bb1651(re-derived after mergingorigin/main, so no STALE TREE warning) — 24 commands, all runpnpm check:nul-bytescheck-nul-bytes: OK (scanned 7611 text file(s) ... no raw ASCII control bytes)+ a direct control-byte scan of the changed file: no hitspnpm check:bash32-floor✓ check-bash32-floor: 27 tracked shell file(s) ... name no bash 4+ construct— the new case is 3.2-cleannode scripts/check-self-test-wired.mjs✓ ... every one of the 173 script(s) CI runs that ship a --self-test has that self-test run by CIcheck-governed-merges.mjs --test scripts/pm/os-verify-lock.sh✅ NOT governed — ordinary queue landing applies16 of the 24 derived gate commands ran green. The other 8 are ⊘ NOT MEASURED, each by name and each a missing dependency in this container, not a red gate:
node packages/lint/scripts/check-reference-carrier-shape.mjsand its--self-test— exit 3,PREREQUISITE NOT MET — the dependency typescript is not installednode scripts/check-ci-filter-parity.mjs— exit 3, dependencyyamlnode scripts/check-closing-keyword-parity.mjsand its--self-test— exit 3, dependencyyamlpnpm check:driver-memory-census— exit 3, dependencytypescriptnode scripts/check-comment-mask-corpus.mjs— exit 1,ERR_MODULE_NOT_FOUNDfor@typescript-eslint/parser(a missing module, not a gate failure)pnpm --filter @objectstack/spec run check:llms-txt— exit 1,sh: 1: tsx: not foundCI runs all of them.
Changeset
skip-changeset. AGENTS.md: a changeset is owed for "anything that publishes … ⛔ neverskip-changeset: that label is for a diff that publishes nothing from any released package." This diff is one file underscripts/pm/, which no package publishes.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code